#include "Cache.h"
#include <iostream>

CacheItem::CacheItem()
{
    filesize = -1;
    data = (char *)malloc(1);
    if(pthread_mutex_init(&itemLock, NULL) != 0)
    {
        //free(itemLock);
        perror("Could not instantiate cache item lock.");
        exit(-1);
    }
}
CacheItem::CacheItem(long long length, int fd)
{
    filesize = length;
    lseek(fd, 0, SEEK_SET);
    if(filesize < 0)
    {
        perror("Could not read file.");
        exit(0xBADA);
    }
    else
    {
        data = (char *)calloc(sizeof(char),filesize);
        long long counter = 0;
        while((filesize - counter) > BUFSIZE)
        {
            read(fd,data + counter,BUFSIZE);
            counter += BUFSIZE;
        }
        read(fd,data + counter,filesize - counter);
    }
    if(pthread_mutex_init(&itemLock, NULL) != 0)
    {
       // free(itemLock);
        perror("Could not instantiate cache item lock.");
        exit(-1);
    }
}
CacheItem::~CacheItem()
{
 //   free(data);
}
Cache::Cache()
{
    currentCacheSize = 0;
    maxCacheSize = MAXCACHE;
}
struct CacheItem Cache::FetchFromCache(string path)
{
    pthread_mutex_lock(&cache[path].itemLock);
    struct CacheItem item = cache[path];
    //check if item exists in map
    if(item.filesize == -1)
    {
        int fd = open(path.c_str(),O_RDONLY);
        if(fd != -1)
        {
            
            long long length = lseek(fd, 0, SEEK_END);
          //  cout << "File length: " << length << endl;
            item = CacheItem(length,fd);
            close(fd);
            //ASSUME EACH FILE IS < CACHE SIZE
            CacheInsert(path,item);
        }
    }
    pthread_mutex_unlock(&cache[path].itemLock);
    return cache[path];
}
void Cache::CacheInsert(string path, struct CacheItem item)
{
    string itemToClear;
    while(currentCacheSize + item.filesize > maxCacheSize)
    {
        itemToClear = files.front();
        currentCacheSize -= cache[itemToClear].filesize;
        cache.erase(itemToClear);
        files.pop();
        cout << path << " deleted" << endl;
        cout << item.filesize << endl;
    }
    cache.erase(path);
    cache.insert(pair<string,struct CacheItem>(path,item));
    currentCacheSize += item.filesize;
    files.push(path);
}
